home *** CD-ROM | disk | FTP | other *** search
- /*
- * Center for Information Technology Integration
- * The University of Michigan
- * Ann Arbor
- *
- * Dedicated to the public domain.
- * Send questions to info@citi.umich.edu
- *
- * BOOTP is documented in RFC 951 and RFC 1048
- * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
- */
-
-
- /*
- * BOOTP (bootstrap protocol) server daemon.
- *
- */
-
-
- #include "global.h"
- #ifdef BOOTPSERVER
- #include <sys/stat.h>
- #include <time.h>
- #include "bootp.h"
- #include "iface.h"
- #include "bootpd.h"
- #include "udp.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: bootpd.c,v 1.14 1997/07/31 00:44:20 root Exp root $";
- #endif
-
- void bootpd (struct iface *iface, struct udp_cb *sock, int16 cnt); /*lint !e15 */
-
- struct udp_cb *Bootpd_cb = NULLUDP;
-
- char homedir[64] = ""; /* bootfile homedirectory */
- char defaultboot[64] = ""; /* default file to boot */
-
- struct host hosts[MHOSTS + 1];
- int Nhosts = 0; /* current number of hosts */
-
- uint32 bp_DefaultDomainNS[BP_MAXDNS] = { 0 };
-
- const char *ArpNames[] =
- {
- "Netrom",
- "Ethernet",
- "AX25",
- "Pronet",
- "Chaos",
- "IEEE 802",
- "ArcNet",
- "AppleTalk"
- };
-
-
- /* Routine declarations */
- static int bootpd_recv (struct udp_cb *sock, struct bootp *bootp);
- static void sendreply (struct bootp *bp, struct iface *iface);
- static void vend_fill (char *vend, struct iface *iface, struct host *hp);
- static void bootpd_request (struct bootp *rq, struct iface *iface);
- #if 0
- static void vend_print (char *vend);
- #endif
-
-
- /* The bootp server. */
- void
- bootpd (struct iface *iface, struct udp_cb *sock, int16 cnt OPTIONAL)
- {
- struct bootp bp_packet;
-
- while (bootpd_recv (sock, &bp_packet) != -1) {
-
- if (readtab () == -1) /* maybe re-read bootptab */
- return;
-
- switch (uchar (bp_packet.op)) {
- case BOOTREQUEST:
- bootpd_request (&bp_packet, iface);
- break;
- case BOOTREPLY:
- default:
- /* Replies are not forwarded, left to the gateway */
- break;
- }
-
- }
-
- }
-
-
-
- /* A packet has been received, read it into a bootp structure. */
- static int
- bootpd_recv (struct udp_cb *sock, struct bootp *bootp)
- {
- struct socket fsock;
- struct mbuf *bp;
- int len;
-
- /* receive the packet */
- len = recv_udp (sock, &fsock, &bp);
- if (len == -1)
- return -1;
-
-
- /* check length of packet */
- if (len < (int) sizeof (struct bootp)) {
- bootp->op = 0;
- free_p (bp);
- return -1;
- }
- /* parse the packet */
- (void) pullup (&bp, (unsigned char *) bootp, sizeof (struct bootp));
-
- free_p (bp);
-
- if (bootp->op != BOOTREPLY && bootp->op != BOOTREQUEST) {
- bootp->op = 0;
- return -1;
- }
- bootp->ciaddr.s_addr = (unsigned long) get32 ((char *) &(bootp->ciaddr));
- bootp->giaddr.s_addr = (unsigned long) get32 ((char *) &(bootp->giaddr));
- return 0;
- }
-
-
-
- /*
- * Process BOOTREQUEST packet.
- *
- * (Note, this version of the bootp.c server never forwards
- * the request to another server. In our environment the
- * stand-alone gateways perform that function.)
- *
- * (Also this version does not interpret the hostname field of
- * the request packet; it COULD do a name->address lookup and
- * forward the request there.)
- */
-
- static void
- bootpd_request (struct bootp *rq, struct iface *iface)
- {
- struct bootp *rp;
- char path[64], file[64];
- struct host *hp;
- int n;
- time_t tloc;
- uint32 ipaddr;
- struct arp_type *at;
-
- (void) time (&tloc);
- bp_log ("\nBootpd request packet received %s", ctime (&tloc));
- /* Forwarding not done here. */
- if (rq->giaddr.s_addr) {
- bp_log (" Dropped, giaddr specifies to be forwarded;\n");
- return;
- }
- /* Is a specific host requested? */
- if ((strlen (rq->sname) != 0) && (strcmp (Hostname, rq->sname) != 0)) {
- bp_log (" Dropped, sname specifies server '%s'\n", rq->sname);
- return;
- }
- /* allocate the reply */
- rp = (struct bootp *) callocw (1, sizeof (struct bootp));
-
- if (!rp) {
- bp_log (" Dropped, insufficient memory '%s'\n", rq->sname);
- return;
- }
- /* copy for construction */
- memcpy (rp, rq, sizeof (struct bootp) - sizeof (rp->vend));
-
- rp->op = BOOTREPLY;
-
- hp = NULLHOST;
-
-
- /* If the client doesn't know it's ip address, find one. */
- if (rq->ciaddr.s_addr == 0) {
- /*
- * client doesn't know his IP address,
- * search by hardware address.
- */
- at = &Arp_type[(int) rq->htype];
- bp_log (" Resolved by %s addr %s\n", ArpNames[(int) rq->htype],
- (*at->format) (bp_ascii, rq->chaddr));
-
- for (hp = &hosts[0], n = 0; n < Nhosts; n++, hp++)
- if ((uchar (rq->htype) == hp->htype)
- && (strncmp (rq->chaddr, hp->haddr, (size_t) (int) rq->hlen) == 0))
- break;
-
- /* If the client wasn't found, assign an IP address */
- if (n == Nhosts) {
-
- hp = NULLHOST;
- if (da_assign (iface, rq->chaddr, &ipaddr) != 0) {
- free (rp);
- bp_log (" No dynamic addresses available.\n");
- return;
- } else {
- (void) put32 ((unsigned char *) &(rp->yiaddr), ipaddr);
- bp_log (" Dynamic address assigned: %s\n", inet_ntoa (ipaddr));
- }
- } else {
- bp_log (" Static address assigned: %s\n", inet_ntoa (hp->iaddr.s_addr));
- (void) put32 ((unsigned char *) &(rp->yiaddr), hp->iaddr.s_addr);
- }
-
- } else {
- /* search by IP address */
- bp_log (" Resolve by IP addr %s\n", inet_ntoa (rq->ciaddr.s_addr));
- for (hp = &hosts[0], n = 0; n < Nhosts; n++, hp++)
- if (rq->ciaddr.s_addr == hp->iaddr.s_addr)
- break;
- if (n == Nhosts) {
- hp = NULLHOST;
- bp_log (" Host not found, default values used.\n");
- } else
- bp_log (" Lookup successful.\n");
- (void) put32 ((unsigned char *) &(rp->ciaddr), (uint32) rq->ciaddr.s_addr);
- }
-
- (void) put32 ((unsigned char *) &(rp->siaddr), iface->addr);
-
- /* Determine the bootp file */
- file[0] = 0;
- if (rq->file[0] == 0) { /* if client didn't specify file */
- /* Use the host record file, else the default file */
- if ((hp == NULLHOST) || (hp->bootfile[0] == 0))
- strcpy (file, defaultboot);
- else
- strcpy (file, hp->bootfile);
- } else /* use client specified file */
- strcpy (file, rq->file);
-
- /* If a file is specified, specify the path to the bootp file */
- path[0] = 0;
- if ((*homedir != 0) && (*file != 0)) {
- strcpy (path, homedir);
- strcat (path, "/");
- }
- if (file[0] == '/') /* if absolute pathname */
- strcpy (path, file);
- else
- strcat (path, file);
-
- /* No files are provided here, just return a path. */
- strcpy (rp->file, path);
-
- /* Fill in the vendor information */
- vend_fill (rp->vend, iface, hp);
-
- sendreply (rp, iface);
- free (rp);
-
- }
-
-
-
- #if 0
- static void bootp_print_packet (struct bootp *bp);
-
- /* Print the bootp structure. */
- static void
- bootp_print_packet (struct bootp *bp)
- {
- bp_log ("Packet op code........................%d\n", bp->op);
- bp_log ("hardware address type.................%d\n", bp->htype);
- bp_log ("hardware address length...............%d\n", bp->hlen);
- bp_log ("client sets to zero...................%d\n", bp->hops);
- bp_log ("transaction ID........................%ld\n", bp->xid);
- bp_log ("seconds elapsed since client booted...%d\n", bp->secs);
- bp_log ("unused................................%d\n", bp->unused);
- bp_log ("Client IP address, if known...........%s\n",
- inet_ntoa (bp->ciaddr.s_addr));
- bp_log ("Server supplied IP address............%s\n",
- inet_ntoa (bp->yiaddr.s_addr));
- bp_log ("Server IP address.....................%s\n",
- inet_ntoa (bp->siaddr.s_addr));
- bp_log ("Gateway IP address....................%s\n",
- inet_ntoa (bp->giaddr.s_addr));
- bp_log ("Client hardware address...............%x:%x:%x:%x:%x:%x\n",
- bp->chaddr[0], bp->chaddr[1], bp->chaddr[2],
- bp->chaddr[3], bp->chaddr[4], bp->chaddr[5]);
- bp_log ("Server host name......................'%s'\n", bp->sname);
- bp_log ("Boot file name........................'%s'\n", bp->file);
-
- vend_print (bp->vend);
- }
-
-
-
- static void
- vend_print (char *vend)
- {
- unsigned char ch;
- int size;
- char *start;
- uint32 *ipaddr;
- int i;
-
- start = vend;
-
- bp_log ("Magic Cookie..........................x%02x%02x%02x%02x\n",
- (int) vend[0], (int) vend[1], (int) vend[2], (int) vend[3]);
- vend = vend + 4;
-
- while (((ch = uchar (*vend++)) != BOOTP_END) && (vend - start <= 64))
- switch (ch) {
-
- case BOOTP_PAD: /* They're just padding */
- continue;
- case BOOTP_SUBNET: /* fixed length, 4 octets */
- size = (int) *vend++;
- ipaddr = (uint32 *) vend;
- bp_log ("Vend Subnet...........................%s\n", inet_ntoa (*ipaddr));
- vend += size;
- break;
- case BOOTP_HOSTNAME:
- size = (int) *vend++;
- bp_log ("Vend Hostname.........................%s\n", vend);
- vend += size;
- break;
- case BOOTP_DNS:
- size = (int) *vend++;
- for (i = 0; i < (size / 4); i++) {
- ipaddr = (uint32 *) vend;
- bp_log ("Vend DomainNS.........................%s\n",
- inet_ntoa (*ipaddr));
- vend += 4;
- }
- break;
- case BOOTP_GATEWAY:
- size = (int) *vend++;
- for (i = 0; i < (size / 4); i++) {
- ipaddr = (uint32 *) vend;
- bp_log ("Vend Gateway..........................%s\n",
- inet_ntoa (*ipaddr));
- vend += 4;
- }
- break;
-
-
- default: /* variable field we don't know about */
- size = *vend++;
- vend += size;
- break;
- }
-
- }
- #endif
-
-
-
- static unsigned char cookie[5] = { 99, 130, 83, 99, 0 };
-
-
-
- static void
- vend_fill (char *vend, struct iface *iface, struct host *hp)
- {
- int len;
- int mod;
- int i;
- char *sizep;
-
- /* Magic cookie */
- strcpy (vend, (char *) cookie);
- vend += 4;
-
- /* Send the iface subnet */
- /* Pad so number falls on word boundry */
-
- vend++;
- vend++;
-
- *vend = BOOTP_SUBNET;
- vend++;
- *vend = 4;
- vend++;
- (void) put32 ((unsigned char *) vend, iface->netmask);
- vend += 4;
-
-
- /* Send the DNS */
- if (bp_DefaultDomainNS[0] != 0) {
- /* Pad for allignment */
- vend++;
- vend++;
-
- *vend = BOOTP_DNS;
- vend++;
- sizep = vend;
- vend++;
- for (i = 0; (i < BP_MAXDNS) && (bp_DefaultDomainNS[i] != 0); i++) {
- (void) put32 ((unsigned char *) vend, (uint32) bp_DefaultDomainNS[i]);
- *sizep = *sizep + 4;
- vend += 4;
- }
- }
- /* Send the default gateway */
- if (R_default.iface == iface) {
- vend++;
- vend++;
-
- *vend = BOOTP_GATEWAY;
- vend++;
- *vend = 4;
- vend++;
- (void) put32 ((unsigned char *) vend, R_default.gateway);
- vend += 4;
- }
- /* Send the hostname */
- if (hp != NULLHOST) {
- /* Pad so name begins on a word boundry */
- vend++;
- vend++;
-
- *vend = BOOTP_HOSTNAME;
- vend++;
- *vend = (char) (len = (int) strlen (hp->name) + 1);
- vend++;
- strcpy (vend, hp->name);
- vend += len;
-
- /* Pad to a word. */
- mod = 4 - (len % 4);
- for (i = 0; i < mod; i++) {
- *vend = BOOTP_PAD;
- vend++;
- }
- }
- /* Mark the end of the data */
- *vend = (char) BOOTP_END;
- }
-
-
-
- /*
- * Send a reply packet to the client. 'forward' flag is set if we are
- * not the originator of this reply packet.
- */
- static void
- sendreply (struct bootp *bp, struct iface *iface)
- {
- struct mbuf *buf;
- uint32 faddr;
- int16 length;
- unsigned char *cp;
-
- /*
- * If the client IP address is specified, use that
- * else if gateway IP address is specified, use that
- * else make a temporary arp cache entry for the client's NEW
- * IP/hardware address and use that.
- */
- if (bp->ciaddr.s_addr)
- faddr = get32 ((char *) &(bp->ciaddr));
- else {
- faddr = get32 ((char *) &(bp->yiaddr));
- (void) arp_add (faddr, (int16) (int) bp->htype, bp->chaddr, 0, iface);
- }
-
- if ((buf = qdata ((unsigned char *) bp, sizeof (struct bootp))) == NULLBUF)
- return;
-
- if ((buf = pushdown (buf, UDPHDR)) == NULLBUF)
- return;
-
- length = sizeof (struct bootp) + UDPHDR;
-
- cp = buf->data;
- cp = put16 (cp, IPPORT_BOOTPS); /* Source */
- cp = put16 (cp, IPPORT_BOOTPC); /* Dest */
- cp = put16 (cp, length);
- *cp++ = 0;
- *cp = 0;
-
- (void) ip_send (iface->addr, faddr, UDP_PTCL, 0, 0, buf, length, 0, 0);
- }
-
- #endif /* BOOTPSERVER */
-